iT邦幫忙

2024 iThome 鐵人賽

DAY 12
3
Kubernetes

都什麼年代了,還在學 Kubernetes系列 第 12

學 Kubernetes 的第十二天 - Networking - Ingress

  • 分享至 

  • xImage
  •  

在 Kubernetes 中,Ingress 是一種 API 資源,它用來管理外部 HTTP 和 HTTPS 流量如何進入集群內部的服務。Ingress 通常使用域名和路由規則將外部請求引導到集群內的特定服務,從而實現對服務的公開訪問。

下面是 Ingress 的一個簡單示例,可將所有流量都傳送到同一 Service:

https://ithelp.ithome.com.tw/upload/images/20240926/20168212CJCCB9rrI5.png

為什麼需要 Ingress

Ingress 提供了一個集中管理 HTTP 和 HTTPS 路由的方式,它能夠根據請求的主機名、路徑、Header 等信息,將請求路由到適當的 Kubernetes 服務。這與傳統的 Service 相比,提供了更靈活和細緻的流量控制。使用 Ingress 可以避免每個服務都需要創建一個 LoadBalancer,從而減少了對外部 IP 地址的需求,也降低了運營成本。

Ingress 和 Service LoadBalancer 的差異

  • 流量控制ServiceLoadBalancer 通常會為每個服務創建一個外部負載均衡器,並將所有進來的流量直接轉發到服務的後端 Pod。而 Ingress 則可以根據更複雜的路由規則(如 URL 路徑、主機名)來分發流量。

  • 成本和資源使用LoadBalancer Service 每個服務都需要一個外部負載均衡器,這在雲環境中通常意味著較高的成本。相比之下,Ingress 通常只需要一個負載均衡器來處理多個服務的流量。

  • 功能擴展Ingress 支持多種功能,如 SSL/TLS 終止、基於名稱的虛擬主機、重寫和重定向 URL 等。這些功能通常無法通過 LoadBalancer 直接實現。

應用場景

  1. HTTP/HTTPS 路由:使用 Ingress 將多個域名或 URL 路徑映射到不同的 Kubernetes 服務,實現 Web 應用的公開訪問。
  2. SSL/TLS 終止:使用 Ingress 在集群邊界處處理 SSL/TLS 加密和解密,保護內部流量。
  3. 多服務整合:通過一個 Ingress 入口點來管理和公開多個服務,避免為每個服務分配獨立的外部 IP 地址。

實作

我們必須擁有一個 Ingress 控製器 才能滿足 Ingress 的要求。僅建立 Ingress 資源本身沒有任何效果。Kubernetes 本身並沒有實作 Ingress 控製器,我們可以從許多 Ingress 控製器中進行選擇並部署,例如 ingress-nginx。本次我們使用 ingress-nginx 作為我們的 Ingress 控製器。

開始之前

為了給 ingress 部署外部 IP,請確認叢集安裝了 MetalLB。安裝方式請參考之前的 Service 章節。

安裝 Ingress controller

  • 使用官方提供的組態檔案進行安裝
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.11.1/deploy/static/provider/cloud/deploy.yaml
  • 檢驗 ingress-nginx controller 安裝結果
kubectl get all -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
pod/ingress-nginx-admission-create-85zzj    0/1     Completed   0          2m12s
pod/ingress-nginx-admission-patch-8kmgv     0/1     Completed   0          2m12s
pod/ingress-nginx-controller-666487-phxw4   1/1     Running     0          2m12s

NAME                                         TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)
             AGE
service/ingress-nginx-controller             LoadBalancer   10.96.18.93    172.20.175.140   80:30655/TCP,443:30748/TCP   2m12s
service/ingress-nginx-controller-admission   ClusterIP      10.96.219.16   <none>           443/TCP
             2m12s

NAME                                       READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ingress-nginx-controller   1/1     1            1           2m12s

NAME                                              DESIRED   CURRENT   READY   AGE
replicaset.apps/ingress-nginx-controller-666487   1         1         1       2m12s

NAME                                       STATUS     COMPLETIONS   DURATION   AGE
job.batch/ingress-nginx-admission-create   Complete   1/1           10s        2m12s
job.batch/ingress-nginx-admission-patch    Complete   1/1           11s        2m12s

實作 Ingress

我們首先建立兩個 nginx Deployment 應用 foo, bar,以及對應的 service 資源。

組態檔案: ingress-test-app.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-foo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-foo
  template:
    metadata:
      labels:
        app: nginx-foo
    spec:
      initContainers:
      - name: modify-index-html
        image: busybox
        command: ["/bin/sh", "-c"]
        args:
          - echo "foo" > /usr/share/nginx/html/index.html
        volumeMounts:
        - name: web-content-foo
          mountPath: /usr/share/nginx/html
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
        volumeMounts:
        - name: web-content-foo
          mountPath: /usr/share/nginx/html
      volumes:
      - name: web-content-foo
        emptyDir: {}

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-foo-service
spec:
  selector:
    app: nginx-foo
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-bar
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-bar
  template:
    metadata:
      labels:
        app: nginx-bar
    spec:
      initContainers:
      - name: modify-index-html
        image: busybox
        command: ["/bin/sh", "-c"]
        args:
          - echo "bar" > /usr/share/nginx/html/index.html
        volumeMounts:
        - name: web-content-bar
          mountPath: /usr/share/nginx/html
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80
        volumeMounts:
        - name: web-content-bar
          mountPath: /usr/share/nginx/html
      volumes:
      - name: web-content-bar
        emptyDir: {}

---
apiVersion: v1
kind: Service
metadata:
  name: nginx-bar-service
spec:
  selector:
    app: nginx-bar
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
  • 建立資源
kubectl apply -f ingress-test-app.yaml

接下來,我們會實現以下情境並測試。

Basic Ingress

這是最基本的路由情境,僅暴露單一的 Service。

組態檔案: ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: basic-ingress
spec:
  ingressClassName: nginx
  defaultBackend:
    service:
      name: nginx-foo-service
      port:
        number: 80
  • 部署 ingress
kubectl apply -f ingress.yaml
  • 等待一段時間,直到 ingress 分配地址
kubectl get ingress
NAME            CLASS   HOSTS   ADDRESS          PORTS   AGE
basic-ingress   nginx   *       172.20.175.140   80      26m
  • 進入 control-plane 節點,測試 ingress 服務
$ docker exec -it wslkind-control-plane /bin/sh
# curl 172.20.175.140
foo
  • 清理 ingress 資源
kubectl delete -f ingress.yaml

Path-Based Ingress

這個路由方法是以路徑為條件,將流量導向不同的 Service。

示意圖如下:
https://ithelp.ithome.com.tw/upload/images/20240926/20168212lnj0tfiFcd.png

組態檔案: ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: path-ingress
  annotations:
    # URL 重定向。
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: nginx-foo-service
            port:
              number: 80
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: nginx-bar-service
            port:
              number: 80
  • 部署 ingress
kubectl apply -f ingress.yaml

一樣等待一段時間,直到 ingress 分配地址。

  • 進入 control-plane 節點,測試 ingress 服務
$ docker exec -it wslkind-control-plane /bin/sh
# curl 172.20.175.140:80/foo
foo
# curl 172.20.175.140:80/bar
bar
  • 清理 ingress 資源
kubectl delete -f ingress.yaml

Host-Based Ingress

這個路由方法是以 Hostname 為條件,將流量導向不同的 Service。

示意圖如下:
https://ithelp.ithome.com.tw/upload/images/20240926/20168212kFT78cHRx9.png

由於 host 是我們自定義的,需要修改訪問環境的 hosts 表。我們是在 control-plane 節點測試,需要在這個節點內修改 hosts。

  • 進入 control-plane 節點,安裝文本編輯器 vim
docker exec -it wslkind-control-plane /bin/sh
# apt-get update
# apt-get install vim
  • 使用 vim /etc/hosts 編輯 hosts 列表
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.18.0.3      wslkind-control-plane
fc00:f853:ccd:e793::3   wslkind-control-plane

Basic Ingress 的實作中我們已經得知,ingress 的 IP 是 172.20.175.140

  • 最下面加入 172.20.175.140 foo.example.com 保存退出

  • 測試 foo.example.com

curl foo.example.com
---
foo
  • 重新修改 /etc/hosts,將剛剛加入的內容修改為 172.20.175.140 bar.example.com 保存退出

  • 測試 bar.example.com

# curl bar.example.com
---
bar

小結

Ingress 提供了強大的 HTTP/HTTPS 流量管理能力,適合那些需要集中管理多個服務入口、SSL/TLS 加密或複雜路由規則的應用場景。

Ingress 和 Ingress Controller 的功能與 AWS 上的 ELB (Elastic Load Balancer) 類似。對於熟悉 AWS 的朋友,可以藉由理解 AWS ELB 開始入手來學習 Ingress 的概念。


參考


上一篇
學 Kubernetes 的第十一天 - Networking - DNS 條目
下一篇
學 Kubernetes 的第十三天 - Storage - Volume
系列文
都什麼年代了,還在學 Kubernetes37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言